package cn.mibcxb.java.dolphin.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;

import cn.mibcxb.java.dolphin.common.Command;
import cn.mibcxb.java.dolphin.common.Commons;
import cn.mibcxb.java.dolphin.common.DolphinData;
import cn.mibcxb.java.dolphin.exception.DolphinException;

public class DolphinConsole {
	private static final String DEFAULT_PROMPT = "dolphin";
	private static final String CHAR_SPACE = " ";
	public static final String CMD_PREFIX = "CMD:";
	private Receiver mReceiver = null;
	private Sender mSender = null;
	private User mUser = null;
	private String mPrompt = DEFAULT_PROMPT;
	private boolean isRunning = true;
	private HashMap<InetAddress, Dolphin> mList = null;

	public DolphinConsole() {
		super();
		init();
	}

	public void init() {
		mReceiver = Receiver.getInstance(this);
		mSender = Sender.getInstance(this);
		mReceiver.start();
		mSender.start();
		mList = new HashMap<InetAddress, Dolphin>();
		mUser = new User(0, "default");
	}

	public void exit() {
		isRunning = false;
		System.out.println("Bye!");
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		DolphinConsole console = new DolphinConsole();

		BufferedReader cmdReader = null;
		String cmdStr = null;
		try {
			cmdReader = new BufferedReader(new InputStreamReader(System.in));
			Command cmd = null;
			while (console.isRunning) {
				console.printPromt(console.mPrompt);
				cmdStr = cmdReader.readLine();
				cmd = console.getCommand(cmdStr);
				console.dispatchCommand(console, cmd, cmdStr);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != cmdReader) {
				try {
					cmdReader.close();
				} catch (IOException e) {
				}
			}
		}

		console.mReceiver.stop();
		console.mSender.stop();
		console = null;
	}

	private Command getCommand(String str) {
		// System.out.println("Console input : " + str);
		if (StringUtils.equalsIgnoreCase(str, CMD_PREFIX + "exit")) {
			return Command.EXIT;
		} else if (StringUtils.equalsIgnoreCase(str, CMD_PREFIX + "login")) {
			return Command.LOGIN;
		} else if (StringUtils.equalsIgnoreCase(str, CMD_PREFIX + "list")) {
			return Command.LIST;
		} else if (StringUtils.startsWithIgnoreCase(str, CMD_PREFIX + "connect"
				+ CHAR_SPACE)) {
			return Command.CONNECT;
		} else if (StringUtils.startsWithIgnoreCase(str, CMD_PREFIX + "chat"
				+ CHAR_SPACE)) {
			return Command.CHAT;
		} else if (StringUtils.equalsIgnoreCase(str, CMD_PREFIX + "user")
				|| StringUtils.startsWithIgnoreCase(str, CMD_PREFIX + "user"
						+ CHAR_SPACE)) {
			return Command.USER;
		}
		return Command.INVALID;
	}

	private void dispatchCommand(DolphinConsole console, Command cmd,
			String cmdStr) throws DolphinException {
		switch (cmd) {
		case EXIT:
			console.exit();
			break;
		case LOGIN:
			// TODO login
			break;
		case LIST:
			console.listFriend();
			break;
		case CONNECT:
			console.connect(cmdStr);
			break;
		case CHAT:
			console.chat(console.mSender, cmdStr);
			break;
		case INVALID:
			printMessage("The command is invalid.");
			break;
		case USER:
			console.operateUser(cmdStr);
			break;
		default:
			break;
		}
	}

	public void send(DolphinData data) {
		mSender.send(data);
	}

	public void dispatchData(DolphinData data) {
		InetAddress addr = data.getFromAddr();
		Dolphin dolphin = getFriend(addr);
		if (null != dolphin) {
			dolphin.receive(data);
		} else {
			dolphin = new Dolphin(this, 0, data.getName(), data.getFromAddr());
			mList.put(dolphin.getAddress(), dolphin);
			dolphin.receive(data);
		}
	}

	public void addDolphin(Dolphin dolphin) {
		dolphin.setId(mList.size() + 1);
		// mList.put(dolphin.getName(), dolphin);
	}

	public Dolphin getFriend(String name) {
		return mList.get(name);
	}

	public Dolphin getFriend(InetAddress addr) {
		Dolphin dolphin = null;
		Set<InetAddress> entires = mList.keySet();
		Iterator<InetAddress> iterator = entires.iterator();
		while (iterator.hasNext()) {
			InetAddress key = iterator.next();
			Dolphin temp = mList.get(key);
			if (temp.getAddress().equals(addr)) {
				dolphin = temp;
				break;
			}
		}
		return dolphin;
	}

	private void printPromt(String prompt) {
		System.out.print(prompt + ">");
	}

	public void printMessage(String msg) {
		synchronized (this) {
			System.out.println();
		}
		System.out.println(msg);
	}

	private void listFriend() {
		Set<InetAddress> entires = mList.keySet();
		Iterator<InetAddress> iterator = entires.iterator();
		while (iterator.hasNext()) {
			InetAddress key = iterator.next();
			Dolphin dolphin = mList.get(key);
			System.out
					.println(dolphin.getName() + " : " + dolphin.getAddress());
		}
	}

	private void connect(String cmdStr) throws DolphinException {
		if (StringUtils.isNotBlank(cmdStr)) {
			String[] temp = cmdStr.split(CHAR_SPACE);
			if (temp.length > 1) {
				String addr = temp[1];
				Dolphin dolphin = null;
				InetAddress address = null;
				try {
					address = InetAddress.getByName(addr);
					dolphin = getFriend(address);
					if (null == dolphin) {
						dolphin = new Dolphin(this, 0, addr, address);
					} else {
						if (!dolphin.isShowing()) {
							dolphin.reopen();
						}
					}
				} catch (UnknownHostException e) {
					throw new DolphinException(e);
				}
				mList.put(dolphin.getAddress(), dolphin);
			}
		}
	}

	private void chat(Sender sender, String cmdStr) throws DolphinException {
		if (StringUtils.isNotBlank(cmdStr)) {
			String[] temp = StringUtils.split(cmdStr, CHAR_SPACE, 3);
			if (temp.length == 3) {
				String addr = null;
				if (Commons.isIP(temp[1])) {
					addr = temp[1];
				} else {
					Dolphin dolphin = mList.get(temp[1]);
					if (null != dolphin) {
						addr = StringUtils.removeStart(dolphin.getAddress()
								.toString(), "/");
					} else {
						System.out.println("Do not connect with friend "
								+ temp[1]);
						return;
					}
				}
				DolphinData data = null;
				try {
					data = new DolphinData(Command.CHAT,
							InetAddress.getByName(addr), mUser.getmName());
				} catch (UnknownHostException e) {
					throw new DolphinException(e);
				}
				data.setMsg(temp[2]);
				sender.send(data);
			}
		}
	}

	private void operateUser(String cmdStr) {
		if (StringUtils.isNotBlank(cmdStr)) {
			String[] temp = StringUtils.split(cmdStr, CHAR_SPACE, 3);
			switch (temp.length) {
			case 1:
				printMessage("Current User = " + mUser.getmId() + ":"
						+ mUser.getmName());
				break;
			case 3:
				if (StringUtils.equalsIgnoreCase(temp[1], "name")) {
					if (StringUtils.isNotBlank(temp[2])) {
						mUser.setmName(temp[2]);
						printMessage("User name set : " + temp[2]);
					}
				} else {
					printMessage("User name can not be NULL.");
				}
				break;
			default:
				break;
			}
		}

	}

	public String getmPrompt() {
		return mPrompt;
	}

	public void setmPrompt(String mPrompt) {
		this.mPrompt = mPrompt;
	}

	public User getmUser() {
		return mUser;
	}

	public void setmUser(User mUser) {
		this.mUser = mUser;
	}
}
